/*
 * Database.java
 *
 * Car Manager
 *
 * Copyright (C) 2005 Tommi Laukkanen
 * http://www.substanceofcode.com
 *
 * Created on June 6th 2005, 19:52
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package com.substanceofcode.carmanager.model;

import javax.microedition.rms.*;
import java.util.*;
import java.io.EOFException;

/** This wrapper class for the RecordStore */
public abstract class Database {
    
    /**
     * The database storing all the records and the last
     * used recordID in position 1
     */
    protected volatile RecordStore database = null;
    
    /** The Vector of used recordIDs that are in the database */
    protected volatile Vector recordIDs = null;
    
    /** The last used ID in the database */
    protected int lastID = 1;
    
    /** The object used to compare two records and see if they are equal */
    protected RecordComparator rc = null;
    
    /** Open database */
    public void open(String fileName) 
            throws RecordStoreNotFoundException,
                   RecordStoreException,
                   RecordStoreFullException {
        database = RecordStore.openRecordStore(fileName, true);
        recordIDs = new Vector(); 
        try {
            if (database.getNumRecords() != 0) {
                try {
                    lastID = Integer.valueOf( new String(database.getRecord(1))).intValue();
                    for (int i = 1; i <= lastID; i++) {
                        recordIDs.addElement(new Integer(i));
                    }
                } catch (InvalidRecordIDException iri) {
                    System.out.println("InvalidRecordID!");
                    throw new RecordStoreException(iri.getMessage());
                }
            }
        } catch (RecordStoreNotOpenException rsno) {
            System.out.println("RecordStoreNotOpen: " + rsno.toString());
            throw new RecordStoreException(rsno.getMessage());
        }
    }
    
    /**
     * Close the database and remove it from
     * persistant storage if it is empty.
     */
    public void close() throws RecordStoreNotOpenException,
            RecordStoreException {
        if (database.getNumRecords() == 0) {
            String fileName = database.getName();
            database.closeRecordStore();
            database.deleteRecordStore(fileName);
        } else {
            database.closeRecordStore();
        }
    }
    
    /** Remove the database from persistant storage */
    public void cleanUp(String fileName) throws RecordStoreNotFoundException,
            RecordStoreException {
        RecordStore.deleteRecordStore(fileName);
        lastID=1;
        open(fileName);
    }
    
    /** Add the record to the database */
    public synchronized void add(String record)
    throws RecordStoreNotOpenException,
            RecordStoreFullException,
            RecordStoreException {
        if (database.getNumRecords() != 0) {
            database.addRecord(record.getBytes(), 0, record.getBytes().length);
            recordIDs.addElement(new Integer(++lastID));
            database.setRecord(1, (String.valueOf(lastID)).getBytes(),
                    0, (String.valueOf(lastID)).length());
        } else {
            recordIDs.addElement(new Integer(++lastID));
            database.addRecord((String.valueOf(lastID)).getBytes(),
                    0, (String.valueOf(lastID)).length());
            try {
                database.addRecord(record.getBytes(), 0,
                        record.getBytes().length);
            } catch (RecordStoreException rs) {
                recordIDs.removeElement(new Integer(lastID--));
                database.setRecord(1, (String.valueOf(lastID)).getBytes(),
                        0, (String.valueOf(lastID)).length());
                throw rs;
            }
        }
    }
    
    /** Delete the record from the database and remove that recordID from the
     * vector of used recordIDs.
     */
    public synchronized void delete(String s)
    throws RecordStoreNotOpenException,
            RecordStoreException {
        action(s, null, 0);
    }
    
    /** Find and return a record. */
    public synchronized String search(String s)
    throws RecordStoreNotOpenException, RecordStoreException {
        return (String) action(s, null, 1);
    }
    
    /** 
     * Update the record with the name with the data
     * in the byte[] array.
     */
    public synchronized void update(String s, byte[] data)
    throws RecordStoreNotOpenException, RecordStoreFullException,
            RecordStoreException {
        action(s, data, 2);
    }
    
    /**
     * Go to the index of the record and perform
     * an action.
     */
    private synchronized Object action(String s, byte[] data, int action)
    throws RecordStoreNotOpenException, RecordStoreFullException,
            RecordStoreException {
        if ((action != 1) && (recordIDs.size() == 0)) {
            throw new RecordStoreException();
        }
        Enumeration IDs = recordIDs.elements();
        while (IDs.hasMoreElements()) {
            int index = ((Integer) IDs.nextElement()).intValue();
            try {
                if (rc.compare(database.getRecord(index), s.getBytes())
                == RecordComparator.EQUIVALENT) {
                    switch (action) {
                        case 0:
                            database.deleteRecord(index);
                            recordIDs.removeElement(new Integer(index));
                            return null;
                        case 1:
                            return new String(database.getRecord(index));
                        case 2:
                            database.setRecord(index, data, 0, data.length);
                            return null;
                        default:
                            break;
                    }
                }
            } catch (InvalidRecordIDException iri) {
                System.out.println("Action: Invalid Record ID Exception");
                throw new RecordStoreException(iri.getMessage());
            }
        }
        return null;
    }
    
    /** Return the number of records in the database. */
    public int getNumRecords() throws RecordStoreNotOpenException {
        return database.getNumRecords();
    }
}
